第10章 函数

第十章,函数

散碎

  1. caller 可以找到哪个函数环境中调用了此函数,(不是 this(严格模式不可用
function func(){
    foo()
}
function foo(){
    console.log(foo.caller === func, this === globalThis) // true true
}
func()
  1. function 声明提升并赋值
foo()
fun() // TypeError: fun is not a function
function foo(){ }
var fun = function(){ }

定义函数

new Function('x', 'y', 'return x + y') //(不推荐)

箭头函数

不能使用 arguments、super、new.target、prototype、new

函数名

一般情况

函数引用.name // 函数名标识符
foo.name // 'foo'

三种特殊情况

new Function().name // 'anonymous'
func.bind().name // bound func

function foo() {} 
let obj = { 
 get age() { }, 
 set age(newAge) { } 
} 
let propertyDescriptor = Object.getOwnPropertyDescriptor(obj, 'age'); 
console.log(propertyDescriptor.get.name); // get age
console.log(propertyDescriptor.set.name); // set age

函数参数

  1. arguments[0] 就是第一个参数,arguments[1] 就是第二个参数...
  2. 在非严格模式下,改变 arguements[0] 的值, 会影响第一个具名参数的值,反之亦然。(但并不意味着他们访问同一地址,只是他们会同步;且传入几个参数,那么只有这几个参数会保持同步,后面声明但未传的不会同步)
  3. 严格模式下他们值初始相同,但后续并不同步
  4. 函数参数有自己的作用域,他不能使用函数体的内容,但是以下代码没有问题
const n = 3
function foo(x = 1, y = x * 2, z = n) {}
  1. arguments.callee === 函数本身 (严格模式不可用 callee)

arguments 长度严格取决于 传入的参数,与定义了多少参数无关

尾调用

目前大部分环境都还未实现尾调用的优化;尾调用指的是最后直接返回函数的调用,且外部栈帧真的没必要存在了。

// 是
function dfs(x){
  return dfs(x + 1)
}
dfs(1)

// 不是
function dfs(x){
  return dfs(x) + 1
}
dfs(1)

闭包

闭包的产生,即内部作用域种用到了外部作用域变量

请仔细阅读下方代码

  1. 不用外部函数作用域变量
const overall = 'overall'
function container(){
  const x = 'x'
  function inner(){
    const y = 'y'
    return function content(){
      const z = 'z'
    }
  }
  return inner()
}
console.dir(container())

  1. 用外部函数作用域变量
const overall = 'overall'
function container(){
  const x = 'x'
  function inner(){
    const y = 'y'
    return function content(){
      const z = 'z'
      const closure = x + y
    }
  }
  return inner()
}
console.dir(container())

[[Scopes]] 列表就是作用域链的体现,具体原理就是,词法环境种引用了外部作用域的词法环境,由此链条依次向上查找,构成作用域链。